package middlewares

import (
	"gitee.com/liuxiaowei123/vblog-1.1/app/token"
	tkimpl "gitee.com/liuxiaowei123/vblog-1.1/app/token/impl"
	"gitee.com/liuxiaowei123/vblog-1.1/app/user"
	"gitee.com/liuxiaowei123/vblog-1.1/exception"
	"gitee.com/liuxiaowei123/vblog-1.1/ioc"
	"gitee.com/liuxiaowei123/vblog-1.1/response"
	"github.com/gin-gonic/gin"
)

type TokenAuthor struct {
	tksvc token.TokenService
	// 为鉴权时使用，要判断上下文中的role和中间件中传入的role
	role user.Role
}

func NewTokenAuthor() *TokenAuthor {
	return &TokenAuthor{
		tksvc: ioc.IocController().Get(tkimpl.AppName).(token.TokenService),
	}
}

func (t *TokenAuthor) Author(c *gin.Context) {
	// 获取数据
	cookietk, err := c.Cookie(token.TOKEN_COOKIE_NAME)
	if err != nil {
		response.Failed(c, err)
		return
	}

	// 校验
	vltk := token.NewValiateTokenRequest(cookietk)
	tk, err := t.tksvc.ValiateToken(c.Request.Context(), vltk)
	if err != nil {
		response.Failed(c, err)
		return
	}

	// 获取的数据存放在上下文中
	if c.Keys == nil {
		c.Keys = map[string]any{}
	}
	c.Keys[token.TOKEN_GIN_KEY_NAME] = tk
}

func (t *TokenAuthor) Perm(c *gin.Context) {
	// 获取上下文数据
	tk := c.Keys[token.TOKEN_GIN_KEY_NAME]
	if tk == nil {
		response.Failed(c, exception.NewPermissionDeny("上下文中没有token信息"))
	}
	// v, ok := tk.(token.Token) 错误代码，导致报错
	v, ok := tk.(*token.Token)
	if !ok {
		response.Failed(c, exception.NewPermissionDeny("上下文中的tk不是token.TokenService类型"))
	}

	// 判断用户权限，上下文中的角色和传入的角色是否相同
	if v.Role != t.role {
		response.Failed(c, exception.NewPermissionDeny("role %d not allow", v.Role))
		return
	}
}

// 传入参数的鉴权中间件
func Required(r user.Role) gin.HandlerFunc {
	a := NewTokenAuthor()
	a.role = r
	return a.Perm
}
